// src/server.ts

import express from 'express';
import { createServer } from 'http';
import { WebSocket, WebSocketServer } from 'ws';
import { BrowserManager } from './browser-manager';
import * as path from 'path';

// 初始化 Express 和 HTTP 服务器
const app = express();
const server = createServer(app);
const wss = new WebSocketServer({ noServer: true });

// 初始化浏览器管理器
const browserManager = new BrowserManager();

// 用于跟踪每个会话的客户端连接
// sessionId -> Set<WebSocket>
const sessionClients = new Map<string, Set<WebSocket>>();

// 用于跟踪每个会话的截图推送计时器
// sessionId -> Timer
const sessionTimers = new Map<string, NodeJS.Timeout>();

// 👉 静态文件服务：提供 viewer.html 等前端资源
app.use(express.static(path.join(__dirname, '../public')));

// 👉 REST API: 创建新浏览器会话
app.get('/api/session/start', async (req, res) => {
  const url = (req.query.url as string) || 'https://www.google.com';
  try {
    const sessionId = await browserManager.createSession(url);
    res.json({
      sessionId,
      viewerUrl: `/viewer.html?sessionId=${sessionId}`,
      message: "Browser session started. Connect via WebSocket to view and control."
    });
  } catch (e: any) {
    console.error('Failed to create session:', e);
    res.status(500).json({ error: e.message });
  }
});

// 👉 REST API: 销毁浏览器会话（彻底关闭浏览器）
app.get('/api/session/:id/destroy', async (req, res) => {
  const { id } = req.params;
  const success = await browserManager.destroySession(id);

  // 清理 WebSocket 相关状态
  sessionClients.delete(id);
  const timer = sessionTimers.get(id);
  if (timer) {
    clearInterval(timer);
    sessionTimers.delete(id);
  }

  res.json({ success, message: success ? 'Session destroyed' : 'Session not found' });
});

// 👉 REST API: 获取所有活跃会话（可选）
app.get('/api/sessions', (req, res) => {
  res.json(browserManager.getAllSessions());
});

// 👉 WebSocket 升级处理
server.on('upgrade', (request, socket, head) => {
  const pathname = new URL(request.url!, `http://${request.headers.host}`).pathname;

  if (pathname.startsWith('/ws/')) {
    const sessionId = pathname.split('/ws/')[1];
    const session = browserManager.getSession(sessionId);

    if (!session) {
      socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
      socket.destroy();
      return;
    }

    wss.handleUpgrade(request, socket, head, (ws) => {
      wss.emit('connection', ws, request, session);
    });
  } else {
    socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
    socket.destroy();
  }
});

// 👉 WebSocket 连接处理
wss.on('connection', (ws: WebSocket, request: any, session: any) => {
  const { id: sessionId, page } = session;
  console.log(`🔗 New client connected to session: ${sessionId}`);

  // 1. 将客户端加入该会话的客户端集合
  if (!sessionClients.has(sessionId)) {
    sessionClients.set(sessionId, new Set());
  }
  sessionClients.get(sessionId)!.add(ws);

  // 2. 如果这是第一个客户端，启动截图推送计时器
  if (sessionClients.get(sessionId)!.size === 1) {
    console.log(`🎥 Starting screenshot stream for session: ${sessionId}`);
    const timer = setInterval(async () => {
      const clients = sessionClients.get(sessionId);
      if (!clients || clients.size === 0) {
        clearInterval(timer);
        sessionTimers.delete(sessionId);
        return;
      }

      try {
        // 截图（质量可调）
        const buffer = await page.screenshot({
          type: 'jpeg',
          quality: 60,
          timeout: 3000
        });

        // 广播给所有活跃客户端
        clients.forEach((clientWs) => {
          if (clientWs.readyState === WebSocket.OPEN) {
            clientWs.send(buffer);
          } else {
            // 清理已关闭的连接
            clients.delete(clientWs);
          }
        });
      } catch (e) {
        console.warn(`Screenshot failed for session ${sessionId}:`, e);
        // 如果截图频繁失败，可以考虑关闭会话
      }
    }, 400); // ~2.5 FPS

    sessionTimers.set(sessionId, timer);
  }

  // 3. 接收并处理控制指令（鼠标、键盘）
  ws.on('message', async (data: string) => {
    try {
      const event = JSON.parse(data);

      // 👉 处理鼠标事件
      if (event.type === 'mouse') {
        const { action, x, y } = event;

        // 坐标映射：假设截图尺寸为 1280x720
        // 在生产中，应从 page.viewportSize() 获取动态尺寸
        const { width, height } = await page.viewportSize();
        const targetX = Math.max(0, Math.min(width, x));
        const targetY = Math.max(0, Math.min(height, y));

        if (action === 'click') {
        console.log('click', targetX, targetY);
            
          await page.mouse.click(targetX, targetY);
        } else if (action === 'move') {
          await page.mouse.move(targetX, targetY);
        }
      }

      // 👉 处理滚轮事件
      else if (event.type === 'wheel') {
        await page.mouse.wheel(event.deltaX || 0, event.deltaY || 0);
      }

      // 👉 处理键盘事件
      else if (event.type === 'key') {
        const { key, code } = event;

        // 简单防注入
        if (typeof key !== 'string') return;

        // 特殊键映射
        const keyMap: { [key: string]: string } = {
          'Enter': 'Enter',
          'Escape': 'Escape',
          'Tab': 'Tab',
          'Backspace': 'Backspace',
          'Delete': 'Delete',
          'ArrowUp': 'ArrowUp',
          'ArrowDown': 'ArrowDown',
          'ArrowLeft': 'ArrowLeft',
          'ArrowRight': 'ArrowRight',
          'Home': 'Home',
          'End': 'End',
          'PageUp': 'PageUp',
          'PageDown': 'PageDown',
          // 可扩展...
        };

        const playwrightKey = keyMap[key] || key;

        // 防止危险组合键（可选）
        if (event.ctrlKey && ['\\', '|'].includes(key)) {
          console.warn('Blocked potentially dangerous key combination');
          return;
        }

        // 执行按键
        if (playwrightKey.length === 1 || Object.values(keyMap).includes(playwrightKey)) {
          await page.keyboard.press(playwrightKey);
        }
      }

    } catch (e: any) {
      console.error(`Control action failed in session ${sessionId}:`, e);
      // 可选择发送错误回客户端
      // if (ws.readyState === WebSocket.OPEN) {
      //   ws.send(JSON.stringify({ error: e.message }));
      // }
    }
  });

  // 4. 处理客户端断开连接
  ws.on('close', () => {
    console.log(`🔌 Client disconnected from session: ${sessionId}`);
    const clients = sessionClients.get(sessionId);
    if (clients) {
      clients.delete(ws);
    }

    // 如果没有客户端了，停止截图推送（但保留浏览器实例）
    if (clients?.size === 0) {
      console.log(`⏸️ No clients for session ${sessionId}, stopping stream.`);
      const timer = sessionTimers.get(sessionId);
      if (timer) {
        clearInterval(timer);
        sessionTimers.delete(sessionId);
      }
    }
  });

  ws.on('error', (error) => {
    console.error(`WebSocket error in session ${sessionId}:`, error);
    ws.terminate();
  });
});

// 👉 启动 HTTP 服务器
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`\n🚀 Browser Control Server Running on http://localhost:${PORT}`);
  console.log(`──────────────────────────────────────`);
  console.log(`🎮 Start Session: GET /api/session/start?url=https://example.com`);
  console.log(`🛑 Destroy Session: GET /api/session/:id/destroy`);
  console.log(`📋 Sessions: GET /api/sessions`);
  console.log(`👀 View & Control: /viewer.html?sessionId=xxx`);
  console.log(`──────────────────────────────────────`);
  console.log(`💡 Tip: Open viewer.html to control the remote browser like a remote desktop!`);
});